package com.mini.mybatis.binding;

import com.mini.mybatis.mapping.MappedStatement;
import com.mini.mybatis.mapping.SqlCommandType;
import com.mini.mybatis.session.Configuration;
import com.mini.mybatis.session.SqlSession;

import java.lang.reflect.Method;

/**
 * 映射器方法 - 封装Mapper方法的执行逻辑
 */
public class MapperMethod {
    
    private final SqlCommand command;
    private final MethodSignature method;
    
    public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
        this.command = new SqlCommand(config, mapperInterface, method);
        this.method = new MethodSignature(config, mapperInterface, method);
    }
    
    /**
     * 执行映射器方法
     */
    public Object execute(SqlSession sqlSession, Object[] args) {
        Object result;
        switch (command.getType()) {
            case INSERT: {
                Object param = method.convertArgsToSqlCommandParam(args);
                result = sqlSession.insert(command.getName(), param);
                break;
            }
            case UPDATE: {
                Object param = method.convertArgsToSqlCommandParam(args);
                result = sqlSession.update(command.getName(), param);
                break;
            }
            case DELETE: {
                Object param = method.convertArgsToSqlCommandParam(args);
                result = sqlSession.delete(command.getName(), param);
                break;
            }
            case SELECT:
                if (method.returnsVoid() && method.hasResultHandler()) {
                    // 处理返回void但有ResultHandler的情况
                    executeWithResultHandler(sqlSession, args);
                    result = null;
                } else if (method.returnsMany()) {
                    // 返回集合
                    result = executeForMany(sqlSession, args);
                } else {
                    // 返回单个对象
                    Object param = method.convertArgsToSqlCommandParam(args);
                    result = sqlSession.selectOne(command.getName(), param);
                }
                break;
            default:
                throw new RuntimeException("未知的执行方法: " + command.getName());
        }
        
        if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
            throw new RuntimeException("映射器方法 '" + command.getName() 
                + "' 尝试返回null，但返回类型是基本类型。请考虑返回包装类型或使用@Nullable注解。");
        }
        
        return result;
    }
    
    /**
     * 执行返回多个结果的查询
     */
    private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
        Object param = method.convertArgsToSqlCommandParam(args);
        return sqlSession.selectList(command.getName(), param);
    }
    
    /**
     * 使用ResultHandler执行查询
     */
    private void executeWithResultHandler(SqlSession sqlSession, Object[] args) {
        // 简化实现，暂不支持ResultHandler
        throw new RuntimeException("暂不支持ResultHandler");
    }
    
    /**
     * SQL命令信息
     */
    public static class SqlCommand {
        
        private final String name;
        private final SqlCommandType type;
        
        public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {
            final String methodName = method.getName();
            final Class<?> declaringClass = method.getDeclaringClass();
            
            // 构建statement id: 接口全名.方法名
            String statementName = mapperInterface.getName() + "." + methodName;
            
            MappedStatement ms = null;
            if (configuration.hasMapper(declaringClass)) {
                ms = configuration.getMappedStatement(statementName);
            }
            
            if (ms == null) {
                throw new RuntimeException("无效的绑定语句 (未找到): " + statementName);
            }
            
            name = ms.getId();
            type = ms.getSqlCommandType();
        }
        
        public String getName() {
            return name;
        }
        
        public SqlCommandType getType() {
            return type;
        }
    }
    
    /**
     * 方法签名信息
     */
    public static class MethodSignature {
        
        private final boolean returnsMany;
        private final boolean returnsVoid;
        private final Class<?> returnType;
        private final boolean hasResultHandler;
        
        public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) {
            this.returnType = method.getReturnType();
            this.returnsVoid = void.class.equals(this.returnType);
            this.returnsMany = configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray();
            this.hasResultHandler = false; // 简化实现
        }
        
        /**
         * 将方法参数转换为SQL命令参数
         */
        public Object convertArgsToSqlCommandParam(Object[] args) {
            if (args == null || args.length == 0) {
                return null;
            } else if (args.length == 1) {
                return args[0];
            } else {
                // 多个参数的情况，简化处理
                return args;
            }
        }
        
        public boolean returnsMany() {
            return returnsMany;
        }
        
        public boolean returnsVoid() {
            return returnsVoid;
        }
        
        public Class<?> getReturnType() {
            return returnType;
        }
        
        public boolean hasResultHandler() {
            return hasResultHandler;
        }
    }
}